/*
 * Copyright 2002-2008 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package foo.bar.blog;

import static org.junit.Assert.*;

import org.junit.*;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.ApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.orm.jpa.JpaTemplate;
import org.dbunit.JdbcDatabaseTester;
import org.dbunit.IDatabaseTester;
import org.dbunit.database.DatabaseSequenceFilter;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.DataSetException;
import org.dbunit.dataset.FilteredDataSet;
import org.dbunit.operation.DatabaseOperation;
import foo.bar.blog.core.services.UserService;
import foo.bar.blog.core.services.BlogService;
import foo.bar.blog.core.services.SetupService;
import foo.bar.blog.core.domain.*;
import foo.bar.blog.web.action.ExtendedPaginatedList;
import foo.bar.blog.web.action.ExtendedPaginatedListImpl;

import java.util.*;

/**
 * @author tmjee
 * @version $Date: 2009-07-05 10:12:59 +0000 (Sun, 05 Jul 2009) $ $Id$
 */
public abstract class AbstractDbTestCase {

    static boolean setuped = false;
    static ApplicationContext applicationContext;
    static Properties prop;

    IDatabaseTester databaseTester;

    @BeforeClass
    public static void _beforeClass() throws Exception {
        if (!setuped) {
            prop = new Properties();
            prop.load(AbstractDbTestCase.class.getResourceAsStream("/db_test.properties"));

            Class.forName(prop.getProperty("db.driverName")).newInstance();
            applicationContext = new ClassPathXmlApplicationContext("/x.xml");

            //SetupService setupService = (SetupService) applicationContext.getBean("setupService");
            //setupService.doTableSetup();
            //setupService.doneSetup();

            setuped = true;
        }
    }


    @AfterClass
    public static void _afterClass() {
        if (applicationContext instanceof AbstractApplicationContext) {
            ((AbstractApplicationContext)applicationContext).close();
        }
    }


    @Before
    public void _before() throws Exception {
        databaseTester = new JdbcDatabaseTester(
            prop.getProperty("db.driverName"),
            prop.getProperty("db.url"),
            prop.getProperty("db.username"),
            prop.getProperty("db.password")    
        );
        databaseTester.setSetUpOperation(DatabaseOperation.CLEAN_INSERT);
        databaseTester.setTearDownOperation(DatabaseOperation.DELETE_ALL);
        databaseTester.setDataSet(new FilteredDataSet(new DatabaseSequenceFilter(databaseTester.getConnection()), getDataSet()));
        databaseTester.onSetup();
    }

    @After
    public void _after() throws Exception {
        databaseTester.onTearDown();    
    }


    protected UserService getUserService() {
        return (UserService) applicationContext.getBean("userService");
    }

    protected BlogService getBlogService() {
        return (BlogService) applicationContext.getBean("blogService");
    }

    protected SetupService getSetupService() {
        return (SetupService) applicationContext.getBean("setupService");
    }


    protected JdbcTemplate getJdbcTemplate() {
        return (JdbcTemplate) applicationContext.getBean("jdbcTemplate");    
    }

    protected TransactionTemplate getTransactionTemplate() {
        return (TransactionTemplate) applicationContext.getBean("transactionTemplate");
    }

    protected JpaTemplate getJpaTemplate() {
        return (JpaTemplate) applicationContext.getBean("jpaTemplate");
    }


    protected abstract IDataSet getDataSet() throws DataSetException;


    protected ExtendedPaginatedList createNewPaginatedList() {
        ExtendedPaginatedList paginatedList = new ExtendedPaginatedListImpl();
        paginatedList.setObjectsPerPage(100);
        paginatedList.setPageNumber(1);
        return paginatedList;
    }

    protected ExtendedPaginatedList createNewPaginatedList(int objectsPerPage, int pageNumber) {
        ExtendedPaginatedList paginatedList = new ExtendedPaginatedListImpl();
        paginatedList.setObjectsPerPage(objectsPerPage);
        paginatedList.setPageNumber(pageNumber);
        return paginatedList;
    }

    protected boolean assertIsNull(Object obj1, Object obj2) {
        if (obj1 == null && obj2 == null) {
            return true;
        }
        else if (obj1 != null && obj2 != null) {
            return false;
        }
        else {
            throw new AssertionError("Object nullity doesn't match ["+obj1+"],["+obj2+"]");
        }
    }

    protected void assertByteEquals(byte[] byte1, byte[] byte2) {
        assertEquals(byte1.length ,byte2.length);
        for (int a=0; a<byte1.length; a++) {
            assertEquals(byte1[a], byte2[a]);    
        }
    }

    protected void assertUserEquals(User user1, User user2)  {
        if (!assertIsNull(user1, user2)) {
            assertEquals(user1.getId(),user2.getId());
            assertEquals(user1.getUsername(), user2.getUsername());
            assertEquals(user1.getEmail(), user2.getEmail());
            assertEquals(user1.getExpiryDate(), user2.getExpiryDate());
            assertEquals(user1.getPassword(), user2.getPassword());
            assertCollectionEquals(user1.getMembershipBlogs(), user2.getMembershipBlogs());
            assertCollectionEquals(user1.getOwnershipBlogs(), user2.getMembershipBlogs());
            assertCollectionEquals(user1.getPermissions(), user2.getPermissions());
            assertCollectionEquals(user1.getProperties(), user2.getProperties());
            assertCollectionEquals(user1.getRoles(), user2.getRoles());
        }
    }

    protected void assertUserEquals_simple(User user1, User user2)  {
        if (!assertIsNull(user1, user2)) {
            assertEquals(user1.getId(),user2.getId());
            assertEquals(user1.getUsername(), user2.getUsername());
            assertEquals(user1.getEmail(), user2.getEmail());
            assertEquals(user1.getExpiryDate(), user2.getExpiryDate());
            assertEquals(user1.getPassword(), user2.getPassword());
        }
    }


    protected void assertBlogEquals(Blog blog1, Blog blog2) {
        if (!assertIsNull(blog1, blog2)) {
            assertEquals(blog1.getId(), blog2.getId());
            assertEquals(blog1.getBlogThemeName(), blog2.getBlogThemeName());
            assertEquals(blog1.getCreationDate(), blog2.getCreationDate());
            assertUserEquals_simple(blog1.getCreator(), blog2.getCreator());
            assertEquals(blog1.getDescription(), blog2.getDescription());
            assertCollectionEquals(blog1.getEntries(), blog2.getEntries());
            assertCollectionEquals(blog1.getLinks(), blog2.getLinks());
            assertCollectionEquals(blog1.getMembers(), blog2.getMembers());
            assertEquals(blog1.getModificationDate(), blog2.getModificationDate());
            assertEquals(blog1.getModifier(), blog2.getModifier());
            assertEquals(blog1.getName(), blog2.getName());
            assertUserEquals_simple(blog1.getOwner(), blog2.getOwner());
            assertCollectionEquals(blog1.getTags(), blog2.getTags());
        }
    }

    protected void assertBlogEquals_simple(Blog blog1, Blog blog2) {
        if (!assertIsNull(blog1, blog2)) {
            assertEquals(blog1.getId(), blog2.getId());
            assertEquals(blog1.getBlogThemeName(), blog2.getBlogThemeName());
            assertEquals(blog1.getCreationDate(), blog2.getCreationDate());
            assertUserEquals_simple(blog1.getCreator(), blog2.getCreator());
            assertEquals(blog1.getDescription(), blog2.getDescription());
            assertEquals(blog1.getModificationDate(), blog2.getModificationDate());
            assertEquals(blog1.getModifier(), blog2.getModifier());
            assertEquals(blog1.getName(), blog2.getName());
            assertUserEquals_simple(blog1.getOwner(), blog2.getOwner());
        }
    }

    protected void assertLinkEquals(Link link1, Link link2) {
        if (!assertIsNull(link1, link2)) {
            assertEquals(link1.getId(), link2.getId());
            assertEquals(link1.getName(), link2.getName());
            assertEquals(link1.getCreationDate(), link2.getCreationDate());
            assertUserEquals_simple(link1.getCreator(), link2.getCreator());
            assertEquals(link1.getDescription(), link2.getDescription());
            assertEquals(link1.getLink(), link2.getLink());
            assertEquals(link1.getModificationDate(), link2.getModificationDate());
            assertUserEquals_simple(link1.getModifier(), link2.getModifier());
            assertEquals(link1.getName(), link2.getName());
            assertEquals(link1.getUid(), link2.getUid());
        }
    }

    protected void assertResourceEquals(Resource resource1, Resource resource2) {
        if (!assertIsNull(resource1, resource2)) {
            assertEntryEquals_simple(resource1.getEntry(), resource2.getEntry());
            assertArrayEquals(resource1.getContent(), resource2.getContent());
            assertEquals(resource1.getCreationDate(), resource2.getCreationDate());
            assertUserEquals_simple(resource1.getCreator(), resource2.getCreator());
            assertEquals(resource1.getDescription(), resource2.getDescription());
            assertEquals(resource1.getId(), resource2.getId());
            assertEquals(resource1.getMimeType(), resource2.getMimeType());
            assertEquals(resource1.getModificationDate(), resource2.getModificationDate());
            assertUserEquals_simple(resource1.getModifier(), resource2.getModifier());
            assertEquals(resource1.getName(), resource2.getName());
            assertEquals(resource1.getUid(), resource2.getUid());
        }
    }

    protected void assertTagEquals(Tag tag1, Tag tag2) {
        if (!assertIsNull(tag1, tag2)) {
            assertBlogEquals_simple(tag1.getBlog(), tag2.getBlog());
            assertEquals(tag1.getCreationDate(), tag2.getCreationDate());
            assertUserEquals_simple(tag1.getCreator(), tag2.getCreator());
            assertEquals(tag1.getDescription(), tag2.getDescription());
            assertEquals(tag1.getId(), tag2.getId());
            assertEquals(tag1.getModificationDate(), tag2.getModificationDate());
            assertUserEquals_simple(tag1.getModifier(), tag2.getModifier());
            assertEquals(tag1.getName(), tag2.getName());
            assertEquals(tag1.getUid(), tag2.getUid());
        }
    }

    protected void assertEntryEquals(Entry entry1, Entry entry2) {
        if (!assertIsNull(entry1, entry2)) {
            assertBlogEquals_simple(entry1.getBlog(), entry2.getBlog());
            assertCollectionEquals(entry1.getComments(), entry2.getComments());
            assertEquals(entry1.getContent(), entry2.getContent());
            assertEquals(entry1.getCreationDate(), entry2.getCreationDate());
            assertUserEquals_simple(entry1.getCreator(), entry2.getCreator());
            assertEquals(entry1.getDescription(), entry2.getDescription());
            assertUserEquals_simple(entry1.getModifier(), entry2.getModifier());
            assertEquals(entry1.getName(), entry2.getName());
            assertEquals(entry1.getPublishDate(), entry2.getPublishDate());
            assertEquals(entry1.getState(), entry2.getState());
            assertTagEquals(entry1.getTag(), entry2.getTag());
            assertEquals(entry1.getUid(), entry2.getUid());
        }
    }

     protected void assertEntryEquals_simple(Entry entry1, Entry entry2) {
        if (!assertIsNull(entry1, entry2)) {
            assertBlogEquals_simple(entry1.getBlog(), entry2.getBlog());
            assertEquals(entry1.getContent(), entry2.getContent());
            assertEquals(entry1.getCreationDate(), entry2.getCreationDate());
            assertUserEquals_simple(entry1.getCreator(), entry2.getCreator());
            assertEquals(entry1.getDescription(), entry2.getDescription());
            assertUserEquals_simple(entry1.getModifier(), entry2.getModifier());
            assertEquals(entry1.getName(), entry2.getName());
            assertEquals(entry1.getPublishDate(), entry2.getPublishDate());
            assertEquals(entry1.getState(), entry2.getState());
            assertTagEquals(entry1.getTag(), entry2.getTag());
            assertEquals(entry1.getUid(), entry2.getUid());
        }
    }

    protected void assertRoleEquals(Role role1, Role role2) {
        if (!assertIsNull(role1, role2)) {
            assertEquals(role1.getId(), role2.getId());
            assertEquals(role1.getType(), role2.getType());
        }
    }

    protected void assertCommentEquals(Comment comment1, Comment comment2) {
        if (!assertIsNull(comment1, comment2)) {
            assertEquals(comment1.getContent(), comment2.getContent());
            assertEquals(comment1.getCreationDate(), comment2.getCreationDate());
            assertUserEquals_simple(comment1.getCreator(), comment2.getCreator());
            assertEntryEquals_simple(comment1.getEntry(), comment2.getEntry());
            assertEquals(comment1.getId(), comment2.getId());
        }
    }

    protected void assertPermissionEquals(Permission permission1, Permission permission2) {
        if (!assertIsNull(permission1, permission2)) {
            assertEquals(permission1.getId(), permission2.getId());
            assertEquals(permission1.getType(), permission2.getType());
        }
    }

    protected void assertCollectionEquals(Collection collection1, Collection collection2) {
        if (!assertIsNull(collection1, collection2)) {
            List l1 = new ArrayList(collection1);
            List l2 = new ArrayList(collection2);
            Collections.sort(l1, new IdComparator());
            Collections.sort(l2, new IdComparator());

            assertEquals(l1.size(), l2.size());

            for (int a=0; a< l1.size(); a++) {
                if (!assertIsNull(l1.get(a), l2.get(a))) {
                    assertEquals(l1.get(a).getClass(), l2.get(a).getClass());

                    // user
                    if ((l1.get(a)) instanceof User) {
                        assertUserEquals_simple((User)l1.get(a), (User)l2.get(a));
                    }

                    // blog
                    if ((l1.get(a)) instanceof Blog) {
                        assertBlogEquals_simple((Blog)l1.get(a), (Blog)l2.get(a));
                    }

                    // entry
                    if ((l1.get(a)) instanceof Entry) {
                        assertEntryEquals((Entry)l1.get(a), (Entry)l2.get(a));
                    }

                    // comment
                    if ((l1.get(a)) instanceof Comment) {
                        assertCommentEquals((Comment)l1.get(a), (Comment)l2.get(a));
                    }

                    // link
                    if ((l1.get(a)) instanceof Link) {
                        assertLinkEquals((Link)l1.get(a), (Link)l2.get(a));
                    }

                    // tag
                    if ((l1.get(a)) instanceof Tag) {
                        assertTagEquals((Tag)l1.get(a), (Tag)l2.get(a));
                    }

                    // resource
                    if ((l1.get(a)) instanceof Resource) {
                        assertResourceEquals((Resource)l1.get(a), (Resource)l2.get(a));    
                    }
                }
            }
        }
    }
}
